#pragma once
#include "def.hpp"

int _shudu[10][10] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 7, 5, 6, 4, 9, 8, 2, 3},
    {0, 6, 4, 9, 3, 2, 8, 1, 7, 5},
    {0, 3, 8, 2, 1, 7, 5, 9, 6, 4},
    {0, 7, 6, 4, 2, 5, 1, 3, 8, 9},
    {0, 8, 5, 1, 9, 3, 7, 2, 4, 6},
    {0, 9, 2, 3, 8, 6, 4, 5, 1, 7},
    {0, 4, 9, 7, 5, 1, 2, 6, 3, 8},
    {0, 5, 1, 6, 7, 8, 3, 4, 9, 2},
    {0, 2, 3, 8, 4, 9, 6, 7, 5, 1}};
int _shuduAnswer[10][10];
int _box[10];

void GetShuduValue(int arr[][10]);
void printShudu(int arr[][10]);
void swapMN(int m, int n, int flag);
void CreateFullShudu(void);
void DigShudu(int arr[][10]);
void CreateShuduCNF(int arr[][10], char sudokuName[30]);

/***********************
 * param: arr
 * return: void
 * res: 获取数独的值存入arr数组
***********************/
void GetShuduValue(int arr[][10])
{
    int n, x, y, cnt = 1, i, j;
    for (i = 1; i <= 9; i++)
        for (j = 1; j <= 9; j++)
        {
            while (Llinfo[cnt].value == 0)
                cnt++;
            arr[i][j] = cnt - (i - 1) * 81 - (j - 1) * 9;
            cnt++;
        }
}

/***********************
 * param: arr
 * return: void
 * res: 输入数独数组的值并显示数独
***********************/
void printShudu(int arr[][10])
{
    for (int i = 0; i <= 9; i++)
    {
        for (int j = 0; j <= 9; j++)
        {
            // if (i == 0 && j >= 1)
            //   printf("----");
            if (j == 0 && i >= 1)
                printf("|");
            if (i >= 1 && j >= 1)
            {
                if (arr[i][j] >= 1)
                    printf(" %d |", arr[i][j]);
                else
                    printf("   |");
            }
        }
        printf("\n------------------------------------\n");
    }
}

/***********************
 * param: m(第m行或者列),n(第n行或者列),flag(1表示m，n为行，2表示m，n为列)
 * return: void
 * res: 交换数独的两行或者两列
***********************/
void swapMN(int m, int n, int flag)
{
    if (flag == 1)
    {
        for (int i = 1; i <= 9; i++)
        {
            int temp = _shudu[m][i];
            _shudu[m][i] = _shudu[n][i];
            _shudu[n][i] = temp;
        }
    }
    else
    {
        for (int i = 1; i <= 9; i++)
        {
            int temp = _shudu[i][m];
            _shudu[i][m] = _shudu[i][n];
            _shudu[i][n] = temp;
        }
    }
}

/***********************
 * param: void
 * return: void
 * res:  创造一个数独
***********************/
void CreateFullShudu(void)
{
    int m, flag;
    int count = rand() % 30 + 50;
    while (count--)
    {
        m = rand() % 9 + 1;
        flag = rand() % 2 + 1;
        if (m <= 3)
        {
            swapMN(m, m % 3 + 1, flag);
        }
        else if (m <= 6)
        {
            swapMN(m, m % 3 + 4, flag);
        }
        else
        {
            swapMN(m, m % 3 + 7, flag);
        }
    }
}

/***********************
 * param: arr(空数组)
 * return: void
 * res:  根据已有的完整数独挖洞创造一个数独
***********************/
void DigShudu(int arr[][10])
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            arr[i][j] = _shudu[i][j];
        }
    }
    int cnt = 0;
    int targetCnt = rand() % 10 + 40;
    int x, y;
    while (cnt < targetCnt)
    {
        x = rand() % 9 + 1;
        y = rand() % 9 + 1;
        if (arr[x][y] != 0)
        {
            arr[x][y] = 0;
            cnt++;
        }
    }
}

/***********************
 * param: void
 * return: void
 * res:  创建数独的cnf公式并存入文件
***********************/
void CreateShuduCNF(int arr[][10], char sudokuName[30])
{
    int i, j, n, cnt = 0, hole = 0; // cnt统计子句数
    char holes[20] = "", des[30] = "p cnf 729 ";
    FILE *fp = fopen(sudokuName, "w");
    for (i = 1; i <= 9; i++)
    {
        for (j = 1; j <= 9; j++)
        {
            if (arr[i][j] == 0)
            {
                hole++;
            }
        }
    }
    itoa((11989 + 81 - hole), holes, 10);
    strcat(des, holes);
    strcat(des, "\n");
    fputs(des, fp);
    // 从另一个文件中引入标准SAT公式
    FILE *fp2 = fopen("base.cnf", "r");
    char str[100];
    while (fgets(str, 100, fp2))
    {
        fputs(str, fp);
    }
    // 对于某种特定数独的提示数
    for (i = 1; i <= 9; i++)
    {
        for (j = 1; j <= 9; j++)
        {
            if (arr[i][j] >= 1)
            {
                char str[20] = "", numStr[10];
                int num = (i - 1) * 81 + (j - 1) * 9 + arr[i][j];
                itoa(num, numStr, 10);
                strcat(str, numStr);
                strcat(str, " 0\n");
                cnt++;
                fputs(str, fp);
            }
        }
    }
    fclose(fp);
}